#include <std.h>
#include <pio.h>
#include <system.h>
#include <error.h>
#include <type.h>

#define DATA		0x1f0
#define ERROR		0x1f1
#define WPC			0x1f1
#define SECTCOUNT	0x1f2
#define LBA1		0x1f3
#define LBA2		0x1f4
#define LBA3		0x1f5
#define DRIVE		0x1f6
#define STATUS		0x1f7
#define COMMAND		0x1f7

char *error[]={"no error detected","formatter device error","sector buffer error","ECC circuit error","controller error"};

#define read_status() (inb(STATUS))

int read_error_diag()
{
	u8 code,err;
	err=inb(ERROR);
	if(err&0x80)	{
		printdev("\nMaster error:");
	} else	{
		printdev("\nSlave error:");
	}
	code=err&7;
	if(code>5)
		printdev("\nUnknown error");
	else
		printdev(error[code]);
}

int read_error_operation()
{
	u8 err;
	err=inb(ERROR);
	if(err&0x80)
		printdev("\nBad block");
	if(err&0x40)
		printdev("\nECC error");
	if(err&0x10)
		printdev("\nID found");
	if(err&0x4)
		printdev("\nCommand aborted");
	if(err&0x2)
		printdev("\nTrack 000 not found");
	if(err&1)
		printdev("\nDAM not found");
}

//Drive register:
#define DRIVELBA		0xe0
#define DRIVE0		0
#define DRIVE1		0x10
//bits 3-0 LBA 24-27

//Status register:
#define STATUSBUSY		0x80
#define STATUSREADY		0x40
#define STATUSWFAULT	0x20
#define STATUSSEEK		0x10
#define STATUSSECTSERV	0x8
#define STATUSRCORRECTED 0x4
#define STATUSINDEX		0x2
#define STATUSPREVERROR	0x1


#define CMD_RESET 0x8
#define CMD_READ_SECTORS 0x20

int read_lba28(u8 *buf,u32 lba,u8 sectcount)
{
	u16 data;
	int i;
	start_local_critical();
	outb(WPC,NULL);
	outb(SECTCOUNT,sectcount);
	outb(LBA1,(u8)lba);
	outb(LBA2,(u8)(lba>>8));
	outb(LBA3,(u8)(lba>>16));
	outb(DRIVE,(u8)(DRIVELBA | DRIVE0 | ((lba>>24)&0x0f)));
	outb(COMMAND,CMD_READ_SECTORS);
	printdev("\nWait busy...");
	while(read_status()&STATUSBUSY);
	mdelay(4);
	read_status();
	for(i=0;i<(sectcount*256);i++)	{
		data=sys_inw(DATA);
		buf[2*i]=(u8)data;
		buf[2*i+1]=(u8)(data>>8);
	}
	end_local_critical();
}

int reset_device()
{
	printdev("\nWait busy...");
	while(read_status()&STATUSBUSY);
	outb(WPC,NULL);
	outb(DRIVE,(u8)(DRIVELBA | DRIVE0));
	outb(COMMAND,CMD_RESET);
	printdev("\nWait busy...");
	while(read_status()&STATUSBUSY);
}

int detect_device()
{
	u16 data;
	u8 rb;
	outb(LBA1,0x88);
	rb=inb(LBA1);
	if(rb==0x88)	{
		outb(DRIVE, 0xa0);
		mdelay(4);
		data = inb(STATUS);
		if (data & 0x40)
			printf("Primary master exists\n");
		outb(DRIVE, 0xb0);
		mdelay(4);
		data = inb(STATUS);
		if (data & 0x40)
			printf("Secondary master exists\n");	
		return SUCCESS;
	}
	return FAILED;
}

void ata_irq()
{
	printdev("[ATA IRQ]");
}

void init_ata()
{
	u8 *buf;
	/*printdev("\nATA drive controller starting.."); 
	if(detect_device()==SUCCESS)	{
		request_irq(14,ata_irq);
		reset_device();
		buf=(u8 *)get_mem(512);
		read_lba28(buf,0,1);
		print_mem(buf,512);
		free(buf);
	} else
		printdev("\nNo ATA device found.");*/
}
